package com.hoshiicloud.as2c.minipro.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hoshiicloud.as2c.minipro.dto.CompanyDto;
import com.hoshiicloud.as2c.minipro.dto.ConsumerDto;
import com.hoshiicloud.as2c.minipro.dto.MemberAccountDto;
import com.hoshiicloud.as2c.minipro.dto.MemberDto;
import com.hoshiicloud.as2c.minipro.feign.IdGeneratorService;
import com.hoshiicloud.as2c.minipro.feign.UserService;
import com.hoshiicloud.as2c.minipro.service.ILoginService;
import com.hoshiicloud.as2c.minipro.util.WXCore;
import com.hoshiicloud.common.exception.CommonError;
import com.hoshiicloud.common.exception.ServiceException;
import com.hoshiicloud.common.rpc.Response;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yangcheng
 * @version 1.0
 * @title: LoginServiceImpl
 * @description:
 * @date 2019/5/25 16:11
 * @mail maiboyc@163.com
 */
@Service
public class LoginServiceImpl implements ILoginService {

	// Id主键生成微服务FeignClient
	@Autowired
	private IdGeneratorService idGeneratorService;

	// 用户中心微服务FeignClient
	@Autowired
	private UserService userService;

	/**
	 * 微信登录
	 *
	 * @param companyId     租户ID
	 * @param platformId    平台ID
	 * @param name          昵称
	 * @param sex           性别
	 * @param province      省份
	 * @param city          城市
	 * @param country       国家
	 * @param headimgurl    头像
	 * @param sessionKey    微信sessionKey
	 * @param openId        微信openId
	 * @param appId         appId
	 * @param encryptedData 密文
	 * @param iv            解密参数
	 * @return boolean
	 * @throws Exception
	 */
	@Override
	public Response<Map<String, Object>> wxLogin(Long companyId, Long platformId, String invitationCode, String name, String sex, String province, String city, String country, String headimgurl, String sessionKey, String openId, String appId, String encryptedData, String iv) throws Exception {
		// 返回对象
		Response<Map<String, Object>> result;
		// 解密小程序前端传过来的加密手机号码
		String telephone = decryptPhoneNumber(sessionKey, appId, encryptedData, iv);
		// 手机号码不为空
		if (StringUtils.isNotEmpty(telephone)) {
			// 根据openId和手机号码获取会员信息（只要openId和telephone任意存在都视为老用户，后台查询根据openId or telephone）
			Response<MemberDto> rs = userService.getMemberByWxOpenIdOrMobile(openId, telephone);
			// 根据手机号码获取会员信息
			if (null != rs && rs.getCode() == 200 && null != rs.getData()) {
				// 第n次登录（修改最后一次登录时间），同时查询用户是否在本平台登录过，如果登录过，只修改最后一次登录时间，如果未登录过，新增本平台的数据，同事需改最后一次登录时间
				if (StringUtils.isEmpty(rs.getData().getWxOpenId())) {
					rs.getData().setWxOpenId(openId);
				}
				Response<Long> update_rs = updateMember(rs.getData());
				if (null == update_rs || update_rs.getCode() != 200 || null == update_rs.getData()) {
					throw new ServiceException(CommonError.error("更新租户会员信息失败"));
				} else {
					Response<List<ConsumerDto>> consumer_rs = userService.getConsumers(new ConsumerDto().setMemberId(update_rs.getData()));
					if (null == consumer_rs || consumer_rs.getCode() != 200 || null == consumer_rs.getData()) {
						Response<Long> consumer_save_rs = saveConsumer(update_rs.getData(), companyId, platformId, invitationCode);
						if (null != consumer_save_rs && consumer_save_rs.getCode() == 200 && null != consumer_save_rs.getData()) {
							Response account_rs = saveMemberAccount(consumer_save_rs.getData());
							if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
								throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
							} else {
								result = getMemberWithConsumerInfo(companyId, platformId, openId);
							}
						} else {
							throw new ServiceException(CommonError.error("保存平台会员信息失败"));
						}
					} else {
						result = getMemberWithConsumerInfo(companyId, platformId, openId);
					}
				}
			} else { // 第一次使用微信登录（保存相关信息到数据库）
				Response<Long> member_rs = saveMember(companyId, name, sex, province, city, country, headimgurl, openId, telephone);
				if (null != member_rs && member_rs.getCode() == 200 && null != member_rs.getData()) {
					Response<Long> consumer_rs = saveConsumer(member_rs.getData(), companyId, platformId, invitationCode);
					if (null != consumer_rs && consumer_rs.getCode() == 200 && null != consumer_rs.getData()) {
						Response account_rs = saveMemberAccount(consumer_rs.getData());
						if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
							throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
						} else {
							result = getMemberWithConsumerInfo(companyId, platformId, openId);
						}
					} else {
						throw new ServiceException(CommonError.error("保存平台会员信息失败"));
					}
				} else {
					throw new ServiceException(CommonError.error("保存租户会员信息失败"));
				}
			}
		} else {
			// 手机号码为空
			throw new ServiceException(CommonError.error("解密用户手机号码出错，手机号码为空"));
		}
		return result;
	}

	/**
	 * 手机号+验证码登录(手机号+验证码注册)
	 *
	 * @param mobile 手机号码
	 * @return boolean
	 * @throws ServiceException
	 */
	@Override
	public Response<Map<String, Object>> codeLogin(Long companyId, Long platformId, String mobile, String invitationCode) throws ServiceException {
		// 返回对象
		Response<Map<String, Object>> result;
		Response<MemberDto> rs = userService.getMemberByMobile(companyId,mobile);
		if (null != rs && rs.getCode() == 200 && null != rs.getData()) {
			// 第n次登录（修改最后一次登录时间）
			MemberDto memberDto = rs.getData();
			memberDto.setLastLoginTime(LocalDateTime.now());
			Response<Long> update_rs = userService.updateMember(memberDto);
			if (null == update_rs || update_rs.getCode() != 200 || null == update_rs.getData()) {
				throw new ServiceException(CommonError.error("更新租户会员信息失败"));
			} else {
				Map<String, Object> map = new HashMap<>();
				map.put("companyId", companyId);             // 租户ID
				map.put("platformId", platformId);           // 平台ID
				map.put("mobile", mobile);                   // 手机号码
				result = userService.getMemberWithConsumerInfo(map);
			}
		} else {
			// 第一次使用手机验证码登录（保存相关信息到数据库）
			MemberDto memberDto = new MemberDto();
			memberDto.setCompanyid(companyId);              // 租户ID
			memberDto.setTelephone(mobile);                 // 手机号码
			Response<Long> member_rs = userService.saveMember(memberDto);
			if (null != member_rs && member_rs.getCode() == 200 && null != member_rs.getData()) {
				Long memberId = member_rs.getData();
				Response<Long> consumer_rs = saveConsumer(memberId, companyId, platformId, invitationCode);
				if (null != consumer_rs && consumer_rs.getCode() == 200 && null != consumer_rs.getData()) {
					Long consumerId = consumer_rs.getData();
					Response account_rs = saveMemberAccount(consumerId);
					if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
						throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
					} else {
						Map<String, Object> map = new HashMap<>();
						map.put("companyId", companyId);
						map.put("platformId", platformId);
						map.put("mobile", mobile);
						result = userService.getMemberWithConsumerInfo(map);
					}
				} else {
					throw new ServiceException(CommonError.error("保存平台会员信息失败"));
				}
			} else {
				throw new ServiceException(CommonError.error("保存租户会员信息失败"));
			}
		}
		return result;
	}

	/**
	 * 查询租户会员信息和平台会员信息
	 *
	 * @param param 查询参数
	 * @return Response<Map < String, Object>>
	 */
	@Override
	public Response<Map<String, Object>> getMemberWithConsumerInfo(Map<String, Object> param) {
		return userService.getMemberWithConsumerInfo(param);
	}

	/**
	 * 保存租户会员信息
	 *
	 * @param companyId  租户Id
	 * @param name       昵称
	 * @param sex        性别
	 * @param province   省份
	 * @param city       城市
	 * @param country    国家
	 * @param headimgurl 头像
	 * @param openId     openId
	 * @return Response<Long>
	 */
	private Response<Long> saveMember(Long companyId, String name, String sex, String province, String city, String country, String headimgurl, String openId, String telephone) {
		// 调用主键生成微服务生成主键
		String id = idGeneratorService.queryGeneratorId();
		if (StringUtils.isEmpty(id)) {
			throw new ServiceException(CommonError.error("新增租户会员信息失败,生成ID主键失败"));
		}
		// 调用租户Service检查租户信息是否存在
		Response<CompanyDto> company = userService.getByCompanyId(companyId);
		if (null == company || company.getCode() != 200 || null == company.getData()) {
			throw new ServiceException(CommonError.error("新增租户会员信息失败，没有找到对应的租户信息"));
		}
		// 调用ID生成微服务生成用户编号
		String userCode = idGeneratorService.getComUserCode();
		if (StringUtils.isEmpty(userCode)) {
			throw new ServiceException(CommonError.error("新增租户会员失败,生成会员编号失败"));
		}
		MemberDto memberDto = new MemberDto();
		memberDto.setId(Long.parseLong(id));            // ID
		memberDto.setCompanyid(companyId);              // 租户ID
		memberDto.setNickname(name);                    // 昵称
		// 调用ID生成微服务生成用户编号(生成唯一编号)
		memberDto.setUsercode(getUniqueUserCode(idGeneratorService.getComUserCode()));
		if (!StringUtils.isNotEmpty(memberDto.getNickname())) { // 如果昵称为空
			memberDto.setNickname("好获" + memberDto.getUsercode());
		}
		if (StringUtils.isNotEmpty(sex)) {
			memberDto.setSex(Integer.parseInt(sex));    // 性别
		} else {
			memberDto.setSex(1);
		}
		memberDto.setWxProvince(province);              // 省份
		memberDto.setWxCity(city);                      // 城市
		memberDto.setWxCountry(country);                // 国家
		memberDto.setHeadimage(headimgurl);             // 头像
		memberDto.setWxPic(headimgurl);                 // 微信头像
		memberDto.setWxOpenId(openId);                  // openId
		memberDto.setTelephone(telephone);              // 手机号码
		memberDto.setCreatedby("admin");
		memberDto.setCreatedtime(LocalDateTime.now());
		memberDto.setUpdatedby("admin");
		memberDto.setUpdatedtime(LocalDateTime.now());
		memberDto.setLastLoginTime(LocalDateTime.now());
		memberDto.setDeleted(0);
		return userService.saveMember(memberDto);
	}

	/**
	 * 保存平台消费者信息
	 *
	 * @param memberId
	 * @param companyId
	 * @param platformId
	 * @param invitationCode
	 * @return
	 */
	private Response saveConsumer(Long memberId, Long companyId, Long platformId, String invitationCode) {
		ConsumerDto consumer = new ConsumerDto();
		// 调用主键生成微服务生成主键
		String id = idGeneratorService.queryGeneratorId();
		if (id == null) {
			throw new ServiceException(CommonError.error("新增平台消费者信息失败,生成ID主键失败"));
		}
		// 调用公司微服务检查租户会员信息和租户信息是否存在
		Response member = userService.getMemberById(memberId);
		if (null == member || member.getCode() != 200 || null == member.getData()) {
			throw new ServiceException(CommonError.error("新增平台消费者信息失败，没有查询到对应的租户会员信息"));
		}
		Response company = userService.getById(companyId);
		if (null == company || company.getCode() != 200 || null == company.getData()) {
			throw new ServiceException(CommonError.error("新增平台消费者信息失败，没有查询到对应的租户信息"));
		}
		// 调用平台微服务检查平台信息是否存在
//        Response platform = platformFeignService.getById(entity.getPlatformid());
//        if (platform == null || platform.getCode() != 200 || platform.getData() == null ) {
//            throw new ServiceException(CommonError.error("新增用户基本信息失败，没有查询到对应的平台信息"));
//        }
		//TODO 推荐人可以为空，如果不为空调用第三方服务验证所属机构ID和推荐人ID,暂时还没弄清楚推荐人机构哪里来

		consumer.setId(Long.parseLong(id));             // ID
		consumer.setMemberId(memberId);                 // 租户会员ID
		consumer.setCompanyid(companyId);               // 租户ID
		consumer.setPlatformid(platformId);             // 平台ID
		// 上级ID
		if (!StringUtils.isNotEmpty(invitationCode)) { // 如果不填，默认邀请码为1000962
			invitationCode = "1000962";
		}
		Response consumers = getConsumerByinviteCode(invitationCode);
		if (null != consumers && consumers.getCode() == 200 && null != consumers.getData()) {
			List<ConsumerDto> list = (List<ConsumerDto>) consumers.getData();
			if (CollectionUtils.isNotEmpty(list)) {
				consumer.setParentId(list.get(0).getId());
			} else {
				consumer.setParentId(194L);
			}
		} else {
			consumer.setParentId(194L);
		}
		consumer.setQrcode("http://www.google.com/XXX.jpg");    // 专属二维码(图片服务器不能用，这里存个假的)
		consumer.setInviteCode(getUniqueInviteCode(idGeneratorService.getPlatCousomerCode()));// 推荐码
		consumer.setLevelId(1);                                 // 会员等级
		consumer.setLevelTime(LocalDateTime.now());             // 升级时间
		consumer.setSysToken("T93328432143214321");             // 系统token
		consumer.setPushToken("T93328432143214322");            // 推送token
		consumer.setDeviceToken("T93328432143214323");          // 设备token
		consumer.setRegShare(0);                                // 注册方式（0-普通 1-298推广注册）
		consumer.setChannel(6);                                 // 渠道（1-app 2-微信 3-pc 6-田森o2o）
		consumer.setCreatedby("admin");
		consumer.setCreatedtime(LocalDateTime.now());
		consumer.setUpdatedby("admin");
		consumer.setUpdatedtime(LocalDateTime.now());
		consumer.setDeleted(0);
		Response consumer_rs = userService.saveConsumer(consumer);
		return consumer_rs;
	}

	/**
	 * 保存平台消费者账户信息
	 *
	 * @param consumerId
	 * @return
	 */
	private Response saveMemberAccount(Long consumerId) {
		MemberAccountDto memberAccountDto = new MemberAccountDto();
		// 调用主键生成微服务生成主键
		String id = idGeneratorService.queryGeneratorId();
		if (id == null) {
			throw new ServiceException(CommonError.error("新增平台会员账户失败,生成ID主键失败"));
		}
		// 调用用户基本信息Service检查用户账户信息是否存在
		Response<ConsumerDto> platConsumer = userService.getById(consumerId);
		if (null == platConsumer || platConsumer.getCode() != 200 || null == platConsumer.getData()) {
			throw new ServiceException(CommonError.error("新增平台会员账户失败，没有找到对应的平台基本信息"));
		}
		memberAccountDto.setId(Long.parseLong(id));
		memberAccountDto.setUserId(consumerId);     // 会员ID
		memberAccountDto.setSettlement(2);          // 结算方式  1-日结 2-月结 3-45DAY 4-60DAY 5-90DAY 6-120DAY
		Response account_rs = userService.saveMemberAccount(memberAccountDto);
		return account_rs;
	}

	private Response getConsumerByinviteCode(String inviteCode) {
		ConsumerDto param = new ConsumerDto();
		param.setInviteCode(inviteCode);
		return userService.getConsumers(param);
	}

	/**
	 * 解密加密串获取微信登录用户手机号码
	 *
	 * @param sessionKey    sessionKey
	 * @param appId         appId
	 * @param encryptedData 密文
	 * @param iv            解密参数
	 * @return String 手机号码
	 */
	private String decryptPhoneNumber(String sessionKey, String appId, String encryptedData, String iv) {
		String telephone;
		String decryptString = WXCore.decrypt(appId, encryptedData, sessionKey, iv);
		if (StringUtils.isNotEmpty(decryptString)) {
			JSONObject jsonObject = JSON.parseObject(decryptString);
			telephone = jsonObject.getString("purePhoneNumber");
		} else {
			telephone = "";
		}
		return telephone;
	}

	/**
	 * 更新租户会员最后一次登录时间
	 *
	 * @param entity 更新参数
	 * @return Response<Long>
	 */
	private Response<Long> updateMember(MemberDto entity) {
		entity.setLastLoginTime(LocalDateTime.now());
		entity.setUpdatedtime(LocalDateTime.now());
		entity.setUpdatedby("admin");
		return userService.updateMember(entity);
	}

	/**
	 * 根据租户Id、平台Id、openId获取用户信息
	 *
	 * @param companyId  租户ID
	 * @param platformId 平台ID
	 * @param openId     openId
	 * @return Response<Map < String, Object>>
	 */
	private Response<Map<String, Object>> getMemberWithConsumerInfo(Long companyId, Long platformId, String openId) {
		Map<String, Object> map = new HashMap<>();
		map.put("companyId", companyId);
		map.put("platformId", platformId);
		map.put("openId", openId);
		return userService.getMemberWithConsumerInfo(map);
	}

	/**
	 * 获取唯一的租户会员编号
	 *
	 * @param userCode 会员编号
	 * @return String
	 * @throws ServiceException
	 */
	private String getUniqueUserCode(String userCode) throws ServiceException {
		String result = "";
		if (StringUtils.isNotEmpty(userCode)) {
			// 检查当前生成的userCode是否已经存在
			MemberDto m = new MemberDto();
			m.setUsercode(userCode);
			Response<List<MemberDto>> members = userService.getMembers(m);
			if (null != members && members.getCode() == 200 && members.getData().size() > 0) {
				getUniqueUserCode(idGeneratorService.getComUserCode());
			} else {
				result = userCode;
			}
		} else {
			throw new ServiceException(CommonError.error("新增租户会员失败,生成会员编号失败"));
		}
		return result;
	}

	/**
	 * 获取唯一的平台会员邀请码
	 *
	 * @param inviteCode
	 * @return String 邀请码
	 * @throws ServiceException
	 */
	private String getUniqueInviteCode(String inviteCode) throws ServiceException {
		String result = "";
		if (StringUtils.isNotEmpty(inviteCode)) {
			// 检查当前生成的userCode是否已经存在
			ConsumerDto c = new ConsumerDto();
			c.setInviteCode(inviteCode);
			Response<List<ConsumerDto>> consumers = userService.getConsumers(c);
			if (null != consumers && consumers.getCode() == 200 && consumers.getData().size() > 0) {
				getUniqueInviteCode(idGeneratorService.getPlatCousomerCode());
			} else {
				result = inviteCode;
			}
		}
		return result;
	}

}
